#include "type.h"
#include "syscall.h"
#include "intr.h"
#include "proc.h"

#if (KDEBUG== 1)
#include "ktty.h"
#endif

extern int user_test(void);

PUBLIC struct _intr_handler  intr_handler_array[] ={
	{DIVIDE_ERR,			divide_err,		KERN_PRIV,		NULL},
	{DEBUG_ERR,			debug_err,		KERN_PRIV,		NULL},
	{NMI,				nmi,				KERN_PRIV,		NULL},
	{BREAKPOINT,			breakpoint,		KERN_PRIV,		NULL},
	{OVERFLOW,			overflow,			KERN_PRIV,		NULL},
	{BOUNDARY_RANGE,	boundary_err,		KERN_PRIV,		NULL},
	{UNDEF_OP,			invalid_operation,	KERN_PRIV,		NULL},
	{NON_MATH,			device_not_avail,	KERN_PRIV,		NULL},
	{DOUBLE_FAULT,		double_fault,		KERN_PRIV,		NULL},
	{SEG_OVERRUN,		seg_overrun,		KERN_PRIV,		NULL},
	{INVALID_TSS,			invalid_tss,		KERN_PRIV,		NULL},
	{SEG_NOT_PRE,		seg_not_present,	KERN_PRIV,		NULL},
	{STACK_FAULE,		stack_fault,		KERN_PRIV,		NULL},
	{GENERAL_PROT,		general_protection,	KERN_PRIV,		NULL},
	{PAGE_FAULT,			page_fault,		KERN_PRIV,		NULL},
	{FLOAT_ERR,			float_err,			KERN_PRIV,		NULL},
	{ALIGN_CHECK,		alignment_check,	KERN_PRIV,		NULL},
	{MACHINE_CHECK,		machine_check,		KERN_PRIV,		NULL},
	{SIMD_EXCEPTION,		simd_exception,	KERN_PRIV,		NULL},
	{CLOCK,				clock,			KERN_PRIV,		NULL},
	{KEEBOARD,			keyboard,		KERN_PRIV,		NULL},
	{SERIAL,				serial,			KERN_PRIV,		NULL},
	{IPC,				ipc,				USER_PRIV,		NULL},
	{SYSCALL,			syscall,			USER_PRIV,		NULL},
	{TEST,				user_test,			USER_PRIV,		NULL},
	{INVALID,				NULL,				NULL,			NULL}
};


int do_divide_err(void){
	return 0;
}

int do_debug_err(void){
	return 0;
}

int do_nmi(void){
	return 0;
}

int do_breakpoint(void){
	return 0;
}


int do_overflow(void){
	return 0;
}


int do_boundary_err(void){
	return 0;
}


int do_invalid_operation(void){
	return 0;
}


int do_device_not_avail(void){
	return 0;
}


int do_double_fault(void){
	return 0;
}


int do_seg_overrun(void){
	return 0;
}


int do_invalid_tss(void){
	return 0;
}


int do_seg_not_present(void){
	return 0;
}


int do_stack_fault(void){
	return 0;
}


int do_general_protection(void){
	return 0;
}


int do_page_fault(void){
	return 0;
}

int do_reserved(void){
	return 0;
}

int do_float_err(void){
	return 0;
}


int do_alignment_check(void){
	return 0;
}


int do_machine_check(void){
	return 0;
}


int do_simd_exception(void){
	return 0;
}

static struct proc *clock_on_ready_queue(void){
	struct proc *candidate_proc = cur_proc;

	if (is_proc_in_server_priv(cur_proc->priv)){
		/* do nothing */
	}else if (is_proc_in_user_priv(cur_proc->priv)){
		cur_proc->ticks --;

		if (cur_proc->ticks == 0){
			cur_proc->ticks = DEFAULT_TICK;
			if (cur_proc->priv < USER_PRIV_END){
				proc_de_ready_queue(cur_proc);
				cur_proc->priv ++;
				proc_en_ready_queue(cur_proc);
				cur_proc->status = READY;
				candidate_proc = NULL;
			}
		}
	}
		
	return candidate_proc;
}

static int clock_on_suspend_queue(void){
	struct proc *proc_p = proc_suspend_queue;
	while(proc_p){
		if (proc_p->sleep_ticks > 0){
			proc_p->sleep_ticks --;

			if (proc_p->sleep_ticks == 0){
				proc_p->status = READY;
				proc_de_suspend_queue(proc_p);
				proc_en_ready_queue(proc_p);
			}
		}
	}
	return 0;
}

int do_clock(void){
	struct proc *candidate_proc = NULL;

	clock_on_suspend_queue();
	candidate_proc = clock_on_ready_queue();
	
	sched(candidate_proc);
	return 0;
}

int do_keyboard(void){
	return 0;
}

int do_serial(void){
	return 0;
}

int do_ipc(int ipc_type, struct message *msg){
	struct proc *candidate_proc = NULL;

	if (!msg){
		return 0;
	}

	if (msg_check(msg) == FALSE){
		return 0;
	}

	switch(ipc_type){
	case SEND:
		send(msg);
		candidate_proc = &(proc[msg->dst]);
		break;
	case RECV:
		recv(msg);
		candidate_proc = cur_proc;
		break;
	case NOTIFY:
		notify(msg);
		candidate_proc = cur_proc;
	default:
		break;
	}

	sched(candidate_proc);
	return 0;
}

int do_syscall(struct syscall_t *sys_p){
	int i = 0;	
	
	if ((sys_p->syscall_nr <= SYS_INVALID)  ||  (sys_p->syscall_nr >= SYS_MAX)){
		return 0;
	}


	for ( ; sys_call_table[i].sys_call_nr != SYS_INVALID; i++){
		if (sys_call_table[i].sys_call_nr == sys_p->syscall_nr){
			sys_call_table[i].do_sys(sys_p);
		}
	}

	if (sys_call_table[i].sys_call_nr == SYS_INVALID){
#if (KDEBUG== 1)
		kdebug(" sys_vector %d is invalid", sys_call_nr);
#endif
		return 0;
	}

	sched(cur_proc);
	return 0;
}

/* EOF */



